//
// sync_client.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <fstream>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
    std::string requestPath = "/client.exe";
    try
    {
        if (argc != 3)
        {
            std::cout << "Usage: sync_client <server> <path>\n";
            std::cout << "Example:\n";
            std::cout << "  sync_client www.boost.org /LICENSE_1_0.txt\n";
            return 1;
        }

        boost::asio::io_service io_service;

        // Get a list of endpoints corresponding to the server name.
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(argv[1], "8000");
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        // Try each endpoint until we successfully establish a connection.
        tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        // Form the request. We specify the "Connection: close" header so that the
        // server will close the socket after transmitting the response. This will
        // allow us to treat all data up until the EOF as the content.
        boost::asio::streambuf request;
        std::ostream request_stream(&request);
        //request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";
        request_stream << "GET " << requestPath.c_str() << " HTTP/1.0\r\n";
        request_stream << "Host: " << argv[1] << "\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Params: " << "user_name=manhppassword=123456" << "\r\n";
        request_stream << "Connection: close\r\n\r\n";
        // Send the request.
        boost::asio::write(socket, request);

        // Read the response status line. The response streambuf will automatically
        // grow to accommodate the entire line. The growth may be limited by passing
        // a maximum size to the streambuf constructor.
        boost::asio::streambuf response;
        boost::asio::read_until(socket, response, "\r\n");

        // Check that response is OK.
        std::istream response_stream(&response);
        std::string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        std::string status_message;
        std::getline(response_stream, status_message);

        if (!response_stream || http_version.substr(0, 5) != "HTTP/")
        {
            std::cout << "Invalid response\n";
            return 1;
        }

        if (status_code != 200)
        {
            std::cout << "Response returned with status code " << status_code << "\n";
            return 1;
        }

        // Read the response headers, which are terminated by a blank line.
        boost::asio::read_until(socket, response, "\r\n\r\n");

        // Process the response headers.
        std::string header;
        std::string contentType = ""; // content - type
        std::size_t findPos;

        while (std::getline(response_stream, header) && header != "\r")
        {
            findPos = header.find("Content-Type");
            if (findPos != std::string::npos)
            {
                contentType = header.substr(findPos + 14); // from :
                std::cout << contentType;
            }
            //std::cout << header << "\n";
        }


        if (contentType.find("data") != std::string::npos)
        {
            // process with data
        }
        else
        {
            // file
        }
        //std::cout << "\n";

        // Write whatever content we already have to output.
        //if (response.size() > 0)
        //	std::cout << &response;
        // Read until EOF, writing data to output as we go.
        boost::system::error_code error;
        std::string dataContent = "";
        if (response.size() > 0)
        {
            // append content of respone data if content size remain in buffer is greateer than 0
            dataContent += std::string(boost::asio::buffer_cast<const char*> (response.data()));
        }

        char buff[1024]; // buffer for read content from stream

        while (true) // read until meet eof
        {
            auto len = socket.read_some(boost::asio::buffer(buff), error);

            if (error == boost::asio::error::eof)
            {
                std::cout << " meet eof " << std::endl;
                break;
            }
            else
            {
                if (error)
                {
                    throw boost::system::system_error(error); // Some other error.
                }
            }

            dataContent += buff;
        }

        std::cout << dataContent;

        std::ofstream os("test.exe", std::ios::out | std::ios::binary);

        if (error != boost::asio::error::eof)
        {
            throw boost::system::system_error(error);
        }
    }
    catch (std::exception& e)
    {
        std::cout << "Exception: " << e.what() << "\n";
    }

    return 0;
}
